package org.thirdeye.reader.helper;

import org.thirdeye.reader.constants.GestureConstants;

import android.app.Activity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;

public class GestureFilter extends SimpleOnGestureListener {

	private int swipe_Min_Distance = 100;
	private int swipe_Max_Distance = 350;
	private int swipe_Min_Velocity = 100;
	
	private int mode = GestureConstants.MODE_DYNAMIC;
	private boolean running = true;
	private boolean tapIndicator = false;

	private Activity context;
	private GestureDetector detector;
	private GestureListener listener;

	public GestureFilter(Activity context, GestureListener sgl) {

		this.context = context;
		this.detector = new GestureDetector(context, this);
		this.listener = sgl;
	}

	public void onTouchEvent(MotionEvent event) {

		if (!this.running)
			return;

		boolean result = this.detector.onTouchEvent(event);

		if (this.mode == GestureConstants.MODE_SOLID)
			event.setAction(MotionEvent.ACTION_CANCEL);
		else if (this.mode == GestureConstants.MODE_DYNAMIC) {

			if (event.getAction() == GestureConstants.ACTION_FAKE)
				event.setAction(MotionEvent.ACTION_UP);
			else if (result)
				event.setAction(MotionEvent.ACTION_CANCEL);
			else if (this.tapIndicator) {
				event.setAction(MotionEvent.ACTION_DOWN);
				this.tapIndicator = false;
			}

		}
		// else just do nothing, it's Transparent
	}

	public void setMode(int m) {
		this.mode = m;
	}

	public int getMode() {
		return this.mode;
	}

	public void setEnabled(boolean status) {
		this.running = status;
	}

	public void setSwipeMaxDistance(int distance) {
		this.swipe_Max_Distance = distance;
	}

	public void setSwipeMinDistance(int distance) {
		this.swipe_Min_Distance = distance;
	}

	public void setSwipeMinVelocity(int distance) {
		this.swipe_Min_Velocity = distance;
	}

	public int getSwipeMaxDistance() {
		return this.swipe_Max_Distance;
	}

	public int getSwipeMinDistance() {
		return this.swipe_Min_Distance;
	}

	public int getSwipeMinVelocity() {
		return this.swipe_Min_Velocity;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {

		final float xDistance = Math.abs(e1.getX() - e2.getX());
		final float yDistance = Math.abs(e1.getY() - e2.getY());

		Log.d("Parameters:", "xDistance:" + xDistance + "yDistance:"
				+ yDistance + "velocityX:" + velocityX + "velocityY:"
				+ velocityY);

		if (xDistance > this.swipe_Max_Distance
				|| yDistance > this.swipe_Max_Distance) {
			Log.e("Returning", "Greater than max distance");
			return false;
		}

		velocityX = Math.abs(velocityX);
		velocityY = Math.abs(velocityY);
		boolean result = false;

		int horizontalSwipe = getHorizontalMotion(velocityX, xDistance, e1, e2);
		int verticalSwipe = getVerticalMotion(velocityY, yDistance, e1, e2);
		if (horizontalSwipe != GestureConstants.SWIPE_NONE) {
			if (verticalSwipe != GestureConstants.SWIPE_NONE) {
				int swipe;
				if (verticalSwipe == GestureConstants.SWIPE_DOWN) {
					swipe = (horizontalSwipe == GestureConstants.SWIPE_LEFT) ? GestureConstants.SWIPE_DOWN_LEFT
							: GestureConstants.SWIPE_DOWN_RIGHT;
				} else {
					swipe = (horizontalSwipe == GestureConstants.SWIPE_LEFT) ? GestureConstants.SWIPE_UP_LEFT
							: GestureConstants.SWIPE_UP_RIGHT;
				}
				this.listener.onSwipe(swipe);
			} else {
				this.listener.onSwipe(horizontalSwipe);
			}
			result = true;
		} else if (verticalSwipe != GestureConstants.SWIPE_NONE) {
			this.listener.onSwipe(verticalSwipe);
			result = true;
		}

		return result;
	}

	private int getVerticalMotion(float velocityY, float yDistance,
			MotionEvent e1, MotionEvent e2) {
		if (velocityY > this.swipe_Min_Velocity
				&& yDistance > this.swipe_Min_Distance) {
			if (e1.getY() > e2.getY()) { // bottom to up
				return GestureConstants.SWIPE_UP;
			} else {
				return GestureConstants.SWIPE_DOWN;
			}
		}
		return GestureConstants.SWIPE_NONE;
	}

	private int getHorizontalMotion(float velocityX, float xDistance,
			MotionEvent e1, MotionEvent e2) {
		if (velocityX > this.swipe_Min_Velocity
				&& xDistance > this.swipe_Min_Distance) {
			if (e1.getX() > e2.getX()) {// right to left
				return GestureConstants.SWIPE_LEFT;
			} else {
				return GestureConstants.SWIPE_RIGHT;
			}
		}
		return GestureConstants.SWIPE_NONE;
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		this.tapIndicator = true;
		return false;
	}

	@Override
	public boolean onDoubleTap(MotionEvent arg0) {
		this.listener.onDoubleTap();
		;
		return true;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent arg0) {
		return true;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent arg0) {

		if (this.mode == GestureConstants.MODE_DYNAMIC) { // we owe an ACTION_UP, so we fake an
			arg0.setAction(GestureConstants.ACTION_FAKE); // action which will be converted to an
											// ACTION_UP later.
			this.context.dispatchTouchEvent(arg0);
		}

		return false;
	}

	public static interface GestureListener {
		void onSwipe(int direction);

		void onDoubleTap();
	}

}
